import { Group, Tween } from "@tweenjs/tween.js"
import Screen from "./Screen"

export type TransitionOptions = {
  in: TransitionIn
  out: TransitionOut
  duration: number
}

export abstract class TransitionIn {
  screen: Screen
  progress: number
  setScreen(screen: Screen) {
    this.screen = screen
    this.init()
  }
  setProgress(progress: number) {
    this.progress = progress
  }
  abstract update(dt: number): void
  abstract destroy(): void
  abstract init(): void
}

export abstract class TransitionOut {
  screen: Screen
  progress: number
  setScreen(screen: Screen) {
    this.screen = screen
  }
  setProgress(progress: number) {
    this.progress = progress
  }
  abstract update(dt: number): void
  abstract destroy(): void
  abstract init(): void
}

type CompleteFunc = () => void

/**
 * 场景过渡
 */
export default class Transition {
  in?: TransitionIn
  out?: TransitionOut
  duration?: number
  group?: Group
  initProgress?: number
  completeFunc?: CompleteFunc
  prevScreen?: Screen
  nextScreen?: Screen

  constructor(options: TransitionOptions) {
    this.in = options.in
    this.out = options.out
    this.duration = options.duration
    this.group = new Group()
    this.initProgress = 0
  }

  start() {
    var progress = {
      value: this.initProgress ?? 0
    }
    var tween = new Tween(progress)
      .to({ value: 2 }, this.duration)
      .onUpdate(() => {
        var dt = Date.now()
        if(progress.value > 1) {
          this.in?.setProgress(progress.value - 1)
          this.in?.update(dt)
        } else {
          this.out?.setProgress(progress.value)
          this.out?.update(dt)
        }
      })
      .onComplete(() => {
        if(this.completeFunc) {
          this.completeFunc()
        }
        this.in.destroy()
        this.out.destroy()
        this.destroy()
      })
      .start()
    this.group.add(tween)
  }

  update(dt: number) {
    this.group?.update(dt)
  }

  destroy() {
    this.group = null
    this.in = null
    this.out = null
    this.duration = null
  }

  onComplete(completeFunc: CompleteFunc) {
    this.completeFunc = completeFunc
  }

  setPrevScreen(screen: Screen) {
    this.prevScreen = screen
    this.out.setScreen(screen)
  }

  setNextScreen(screen: Screen) {
    this.nextScreen = screen
    this.in.setScreen(screen)
  }
}